//
// Created by jackzhous on 2019/7/23.
//

#include "opensl_demo_.h"

#ifdef __cplusplus


extern "C" {
#endif

static SLuint32 getChannelMask(SLuint32 numChannels) {
    return numChannels > 1
           ? SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT
           : SL_SPEAKER_FRONT_CENTER;
}

static void openSLCallBack(SLAndroidSimpleBufferQueueItf queue, void *pContext){
    LOG("bufferQueueCallback");
    OpenSLHelper *helper = (OpenSLHelper*)pContext;
    lockNotify(&(helper->lock));
}

void lockInit(LockUtil *lock){
    pthread_mutex_init(lock->mutex, NULL);
    pthread_cond_init(lock->condition, NULL);
    lock->value = 1;
}


void lockWait(LockUtil *lock){
    pthread_mutex_lock(lock->mutex);
    //为0就等待
    while (!lock->value){
        pthread_cond_wait(lock->condition, lock->mutex);
    }
    lock->value = 0;
    pthread_mutex_unlock(lock->mutex);
}

void lockNotify(LockUtil *lock){
    pthread_mutex_lock(lock->mutex);
    lock->value = 1;
    pthread_cond_signal(lock->condition);
    pthread_mutex_unlock(lock->mutex);
}

void lockDestroy(LockUtil *lock){
    lockNotify(lock);
    pthread_cond_destroy(lock->condition);
    pthread_mutex_destroy(lock->mutex);
}


void openSLInit(OpenSLHelper *slHelper){

    slHelper->engineInterface = NULL;
    slHelper->engineObject = NULL;
    slHelper->recorderInterface = NULL;
    slHelper->recorderObject = NULL;
    slHelper->playerInterface = NULL;
    slHelper->playerObject = NULL;
    slHelper->outputMixObject = NULL;

    lockInit(&(slHelper->lock));

    slCreateEngine(&(slHelper->engineObject), 0, NULL, 0, NULL, NULL);
    (*slHelper->engineObject)->Realize(slHelper->engineObject, SL_BOOLEAN_FALSE);

    (*slHelper->engineObject)->GetInterface(slHelper->engineObject, SL_IID_ENGINE, &(slHelper->engineInterface));
}

void openSLDestroy(OpenSLHelper *slHelper){
    lockDestroy(&(slHelper->lock));

    if(slHelper->playerObject){
        (*slHelper->playerObject)->Destroy(slHelper->playerObject);
        slHelper->playerObject = NULL;
        slHelper->playerInterface = NULL;
    }

    if(slHelper->recorderObject){
        (*slHelper->recorderObject)->Destroy(slHelper->recorderObject);
        slHelper->recorderObject = NULL;
        slHelper->recorderInterface = NULL;
    }

    if(slHelper->outputMixObject){
        (*slHelper->outputMixObject)->Destroy(slHelper->outputMixObject);
        slHelper->outputMixObject = NULL;
    }

    slHelper->androidBufferQueueItf = NULL;
    if(slHelper->engineObject){
        (*slHelper->engineObject)->Destroy(slHelper->engineObject);
        slHelper->engineObject = NULL;
        slHelper->engineInterface = NULL;
    }
}


void recorderInit(OpenSLHelper *slHelper, SLuint32 channels, SLuint32 sampleRate){
    //录音源source
    slHelper->ioDevice.locatorType = SL_DATALOCATOR_IODEVICE;       //源头是io设备
    slHelper->ioDevice.deviceType = SL_IODEVICE_AUDIOINPUT;         //音频输入
    slHelper->ioDevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
    slHelper->ioDevice.device = NULL;           //device ID生效的前提必须device为NULL

    slHelper->source.pLocator = &(slHelper->ioDevice);
    slHelper->source.pFormat = NULL;        //已经设置了locator忽略此参数

    //输出
    slHelper->queue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;  //输出到缓冲队列
    slHelper->queue.numBuffers = 2;     //2个缓冲队列

    slHelper->pcmFormat.formatType = SL_DATAFORMAT_PCM;     //录音数据格式
    slHelper->pcmFormat.numChannels = channels;
    slHelper->pcmFormat.samplesPerSec = sampleRate;
    slHelper->pcmFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;        //每个采样点bit
    slHelper->pcmFormat.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
    slHelper->pcmFormat.channelMask = getChannelMask(channels);             //根据声道数确定掩码
    slHelper->pcmFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;             //字节小端模式

    slHelper->sink.pLocator = &(slHelper->queue);
    slHelper->sink.pFormat = &(slHelper->pcmFormat);

    ///Recorder/////
    SLInterfaceID id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
    SLboolean required[] = {SL_BOOLEAN_TRUE};

    (*slHelper->engineInterface)->CreateAudioRecorder(slHelper->engineInterface, &(slHelper->recorderObject)
                                , &(slHelper->source), &(slHelper->sink), 1, id, required);
    (*slHelper->recorderObject)->Realize(slHelper->recorderObject, SL_BOOLEAN_FALSE);

    //Register
    (*slHelper->recorderObject)->GetInterface(slHelper->recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
                                    &(slHelper->androidBufferQueueItf));

    (*slHelper->androidBufferQueueItf)->RegisterCallback(slHelper->androidBufferQueueItf, openSLCallBack, slHelper);

    //start recorder
    (*slHelper->recorderObject)->GetInterface(slHelper->recorderObject, SL_IID_RECORD, &(slHelper->recorderInterface));
    (*slHelper->recorderInterface)->SetRecordState(slHelper->recorderInterface, SL_RECORDSTATE_RECORDING);
}

void playerInit(OpenSLHelper *slHelper, SLuint32 channels, SLuint32 sampleRate){
    //输入源
    slHelper->queue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
    slHelper->queue.numBuffers = 2;

    slHelper->pcmFormat.formatType = SL_DATAFORMAT_PCM;
    slHelper->pcmFormat.numChannels = channels;
    slHelper->pcmFormat.samplesPerSec = sampleRate;
    slHelper->pcmFormat.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
    slHelper->pcmFormat.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
    slHelper->pcmFormat.channelMask = getChannelMask(channels);
    slHelper->pcmFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;

    slHelper->source.pLocator = &(slHelper->queue);
    slHelper->source.pFormat = &(slHelper->pcmFormat);

    //Sink
    (*slHelper->engineInterface)->CreateOutputMix(slHelper->engineInterface,
                                                        &(slHelper->outputMixObject),
                                                        0,
                                                        NULL,
                                                        NULL);
    (*slHelper->outputMixObject)->Realize(slHelper->outputMixObject, SL_BOOLEAN_FALSE);

    slHelper->outputMix.locatorType = SL_DATALOCATOR_OUTPUTMIX;         //输出设备未混音器
    slHelper->outputMix.outputMix = slHelper->outputMixObject;

    slHelper->sink.pLocator = &(slHelper->outputMix);
    slHelper->sink.pFormat = NULL;

    SLInterfaceID  id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
    SLboolean require[] = {SL_BOOLEAN_TRUE};
    (*slHelper->engineInterface)->CreateAudioPlayer(
            slHelper->engineInterface,
            &(slHelper->playerObject),
            &(slHelper->source),
            &(slHelper->sink),
            1,
            id,
            require
            );

    (*slHelper->playerObject)->Realize(slHelper->playerObject, SL_BOOLEAN_FALSE);

    (*slHelper->playerObject)->GetInterface(slHelper->playerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
                        &(slHelper->androidBufferQueueItf));

    (*slHelper->androidBufferQueueItf)->RegisterCallback(slHelper->androidBufferQueueItf, openSLCallBack, slHelper);

    //开始播放
    (*slHelper->playerObject)->GetInterface(slHelper->playerObject, SL_IID_PLAY, &(slHelper->playerInterface));

    (*slHelper->playerInterface)->SetPlayState(slHelper->playerInterface, SL_PLAYSTATE_PLAYING);
}


#ifdef __cplusplus
}
#endif